package edu.ynu.se.xiecheng.achitectureclass.service;

import edu.ynu.se.xiecheng.achitectureclass.common.service.LogicService;
import edu.ynu.se.xiecheng.achitectureclass.dao.CameraDataDao;
import edu.ynu.se.xiecheng.achitectureclass.dao.DeviceRepository;
import edu.ynu.se.xiecheng.achitectureclass.entity.CameraData;
import edu.ynu.se.xiecheng.achitectureclass.entity.Device;
import edu.ynu.se.xiecheng.achitectureclass.entity.Token;
import edu.ynu.se.xiecheng.achitectureclass.dao.TokenRepository;
import edu.ynu.se.xiecheng.achitectureclass.utils.OssUtils;
import edu.ynu.se.xiecheng.achitectureclass.config.ApiConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 摄像头数据服务
 * 负责处理摄像头设备采集的图片数据的存储和查询
 */
@Slf4j
@Service
public class CameraDataService extends LogicService<CameraDataDao, CameraData, Long> {
    private final CameraDataDao cameraDataDao;
    private final DeviceRepository deviceRepository;
    private final TokenRepository tokenRepository;
    private final RestTemplate restTemplate;
    private final ApiConfig apiConfig;
    private final OssUtils ossUtils;

    private static final String TOKEN_TYPE_CAMERA = "CAMERA";

    public CameraDataService(CameraDataDao cameraDataDao, 
                           DeviceRepository deviceRepository,
                           TokenRepository tokenRepository,
                           RestTemplate restTemplate,
                           ApiConfig apiConfig,
                           OssUtils ossUtils) {
        super(cameraDataDao);
        this.cameraDataDao = cameraDataDao;
        this.deviceRepository = deviceRepository;
        this.tokenRepository = tokenRepository;
        this.restTemplate = restTemplate;
        this.apiConfig = apiConfig;
        this.ossUtils = ossUtils;
    }

    /**
     * 查询最近的摄像头抓拍图片
     */
    public List<CameraData> findRecentPhotos(Long deviceId, int limit) {
        return cameraDataDao.findByDeviceIdAndIsDeletedOrderByCreateTimeDesc(deviceId, 0, PageRequest.of(0, limit));
    }

    /**
     * 采集摄像头图片数据
     */
    @Scheduled(initialDelay = 30000, fixedRate = 1800000)
    public void collectCameraData() {
        List<Device> cameraDevices = deviceRepository.findAll().stream()
                .filter(device -> "CAMERA".equals(device.getDeviceType()))
                .collect(Collectors.toList());

        for (Device device : cameraDevices) {
            try {
                // 确保有有效的token
                String cameraToken = ensureCameraToken();
                
                // 调用摄像头API抓拍照片
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                
                MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
                requestParams.add("accessToken", cameraToken);
                requestParams.add("deviceSerial", device.getSerialNumber());
                requestParams.add("channelNo", "1");
                
                ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                    "https://open.ys7.com/api/lapp/device/capture",
                    HttpMethod.POST,
                    new HttpEntity<>(requestParams, headers),
                    new ParameterizedTypeReference<Map<String, Object>>() {}
                );
                
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    Map<String, Object> responseData = response.getBody();
                    String code = responseData.get("code").toString();
                    
                    if ("200".equals(code)) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> data = (Map<String, Object>) responseData.get("data");
                        if (data != null && data.containsKey("picUrl")) {
                            String picUrl = (String) data.get("picUrl");
                            log.info("获取到图片URL: {}", picUrl);
                            
                            // 缩短等待时间，避免签名过期
                            Thread.sleep(500);
                            
                            try {
                                // 使用URI类来确保URL不会被二次编码
                                URI uri = new URI(picUrl);
                                
                                // 创建请求
                                RequestEntity<Void> request = RequestEntity
                                    .get(uri)
                                    .build();
                                
                                // 发送请求获取图片
                                ResponseEntity<byte[]> picResponse = restTemplate.exchange(
                                    request,
                                    byte[].class
                                );
                                
                                if (picResponse.getStatusCode() == HttpStatus.OK && picResponse.getBody() != null) {
                                    // 上传图片到阿里云OSS
                                    String ossUrl = ossUtils.uploadToOSS(picResponse.getBody(), device.getSerialNumber());
                                    
                                    // 保存图片URL到数据库
                                    CameraData cameraData = new CameraData();
                                    cameraData.setDevice(device);
                                    cameraData.setPhotoUrl(ossUrl);
                                    cameraData.setCreateTime(convertToDate(LocalDateTime.now()));
                                    cameraDataDao.save(cameraData);
                                    log.info("成功保存摄像头图片URL到数据库: {}", ossUrl);
                                    
                                    // 缩短等待时间
                                    Thread.sleep(1000);
                                } else {
                                    log.error("获取图片数据失败: {} - 状态码: {}", 
                                        device.getSerialNumber(), picResponse.getStatusCode());
                                }
                            } catch (Exception e) {
                                log.error("处理图片URL失败: {} - {}", picUrl, e.getMessage());
                            }
                        } else {
                            log.error("摄像头返回数据中没有图片URL: {}", device.getSerialNumber());
                        }
                    } else {
                        log.error("获取图片失败: {} - 错误码: {} - 错误信息: {}", 
                            device.getSerialNumber(), code, responseData.get("msg"));
                    }
                } else {
                    log.error("获取图片数据失败: {} - 状态码: {}", 
                        device.getSerialNumber(), response.getStatusCode());
                }
            } catch (Exception e) {
                log.error("采集摄像头数据失败: " + device.getSerialNumber(), e);
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    /**
     * 确保摄像头访问令牌有效
     */
    public String ensureCameraToken() {
        try {
            // 先从数据库查找token
            Optional<Token> tokenOpt = tokenRepository.findByTokenType(TOKEN_TYPE_CAMERA);
            Token token = tokenOpt.orElse(new Token());
            
            // 检查token是否存在且未过期
            if (token.getAccessToken() == null || new Date().after(token.getExpireTime())) {
                String url = "http://42.193.14.241:7000/ysapi/subAccount/getToken";
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);

                Map<String, String> requestBody = new HashMap<>();
                requestBody.put("accountId", apiConfig.getCamera().getAccountId());

                HttpEntity<Map<String, String>> request = new HttpEntity<>(requestBody, headers);

                ResponseEntity<Map<String, Object>> response = restTemplate.exchange(
                        url,
                        HttpMethod.POST,
                        request,
                        new ParameterizedTypeReference<>() {}
                );

                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    Map<String, Object> responseData = response.getBody();
                    log.info("Camera API 返回数据: {}", responseData);

                    Object data = responseData.get("data");
                    if (data instanceof Map) {
                        Map<String, Object> dataMap = (Map<String, Object>) data;
                        String accessToken = (String) dataMap.get("accessToken");
                        long expireTime = Long.parseLong(dataMap.get("expireTime").toString());
                        
                        // 更新token信息
                        token.setTokenType(TOKEN_TYPE_CAMERA);
                        token.setAccessToken(accessToken);
                        token.setExpireTime(new Date(expireTime));
                        tokenRepository.save(token);
                        
                        log.info("成功获取并保存摄像头访问令牌，将在 {} 过期", token.getExpireTime());
                    } else {
                        throw new RuntimeException("未知的数据结构: " + data);
                    }
                } else {
                    throw new RuntimeException("获取摄像头访问令牌失败: " + response.getBody());
                }
            }
            
            return token.getAccessToken();
        } catch (Exception e) {
            log.error("获取摄像头访问令牌失败", e);
            throw new RuntimeException("获取摄像头访问令牌失败", e);
        }
    }

    /**
     * 将LocalDateTime转换为Date
     */
    private Date convertToDate(LocalDateTime dateToConvert) {
        return Date.from(dateToConvert.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 根据时间范围查询照片
     */
    public List<CameraData> findPhotosByTimeRange(Date start, Date end, Integer pageNum, Integer pageSize) {
        if (start == null) {
            // 如果没有开始时间，默认查询最近24小时
            start = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
        }
        if (end == null) {
            end = new Date();
        }
        
        return cameraDataDao.findByCreateTimeBetweenAndIsDeletedOrderByCreateTimeDesc(
            start, 
            end,
            0,
            PageRequest.of(pageNum - 1, pageSize)
        );
    }

    /**
     * 统计时间范围内的照片数量
     */
    public long countPhotosByTimeRange(Date start, Date end) {
        if (start == null) {
            start = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
        }
        if (end == null) {
            end = new Date();
        }
        
        return cameraDataDao.countByCreateTimeBetweenAndIsDeleted(start, end, 0);
    }
}